/*****************************************************************************
*    Copyright (C)2003 Ali Corporation. All Rights Reserved.
*
*    File:    nim_ix2410.c
*
*    Description:    This file contains sharp ix2410 basic function in LLD.
*    History:
*           Date            Athor        Version          Reason
*	    ============	=============	=========	=================
*	1.	Mar.25.2004     David Wang	     Ver 0.1    Create file.
*	2.  08/31/2005	Zhu Jun		Ver 1.1		Unify Tuner's configuration API Functions
*
*****************************************************************************/

#include <sys_config.h>


#include <retcode.h>
#include <types.h>
#include <api/libc/printf.h>
#include <api/libc/string.h>
#include <bus/i2c/i2c.h>
#include <osal/osal.h>
#include "nim_ix2410.h"

static struct QPSK_TUNER_CONFIG_EXT * stIX2410_dev_id[MAX_TUNER_SUPPORT_NUM] = {NULL};
static UINT32 stIX2410_tuner_cnt = 0;
/*****************************************************************************
* INT32 nim_ix2410_init(UINT32* tuner_id, struct QPSK_TUNER_CONFIG_EXT * ptrTuner_Config)
*
* Tuner IX2410 Initialization
*
* Arguments:
*  Parameter1: UINT32 *tuner_id		: allocated tuner id value 
*  Parameter2: struct QPSK_TUNER_CONFIG_EXT * ptrTuner_Config		: pointer for Tuner configuration structure
*
* Return Value: INT32			: Result
*****************************************************************************/
INT32 nim_ix2410_init(UINT32* tuner_id, struct QPSK_TUNER_CONFIG_EXT * ptrTuner_Config)
{
	struct QPSK_TUNER_CONFIG_EXT * tuner_dev_ptr = NULL;
	/* check Tuner Configuration structure is available or not */
	if (ptrTuner_Config == NULL||stIX2410_tuner_cnt>=MAX_TUNER_SUPPORT_NUM)
		return ERR_FAILUE;
	tuner_dev_ptr = (struct QPSK_TUNER_CONFIG_EXT *)MALLOC(sizeof(struct QPSK_TUNER_CONFIG_EXT));
	if(!tuner_dev_ptr)return ERR_FAILUE;
	stIX2410_dev_id[stIX2410_tuner_cnt] = tuner_dev_ptr;
	*tuner_id = stIX2410_tuner_cnt;
	MEMCPY(tuner_dev_ptr, ptrTuner_Config, sizeof(struct QPSK_TUNER_CONFIG_EXT));
	stIX2410_tuner_cnt ++;
	return SUCCESS;
}

/*****************************************************************************
* INT32 nim_ix2410_control(UINT32 freq, UINT8 sym)
*
* Tuner write operation
*
* Arguments:
*  Parameter1: UINT32 freq		: Synthesiser programmable divider
*  Parameter2: UINT8 sym		: symbol rate
*
* Return Value: INT32			: Result
*****************************************************************************/
INT32 nim_ix2410_control(UINT32 tuner_id, UINT32 freq, UINT32 sym)
{
	UINT8 data[4];
	UINT16 Npro,tmp;
	UINT32 Rs, BW;
	UINT8 Nswa;
	UINT8 LFP = 13;
	UINT8 BA = 1;
	UINT8 DIV = 0;
	INT32 result;
	struct QPSK_TUNER_CONFIG_EXT * tuner_dev_ptr = NULL;
	if(tuner_id>=stIX2410_tuner_cnt||tuner_id>=MAX_TUNER_SUPPORT_NUM)
		return ERR_FAILUE;
	tuner_dev_ptr = stIX2410_dev_id[tuner_id];
	/* LFP cut_off */
	Rs = sym;
	if (Rs==0)
		Rs = 45000;
	BW = Rs*135/200;                // rolloff factor is 35%
	if (Rs<6500)  BW = BW + 6000;   // add 3M when Rs<5M, since we need shift 3M to avoid DC
	BW = BW + 2000;                 // add 2M for LNB frequency shifting
//ZCY: the cutoff freq of IX2410 is not 3dB point, it more like 0.1dB, so need not 30%
//	BW = BW*130/100;                // 0.1dB to 3dB need about 30% transition band for 7th order LPF
	BW = BW*108/100;                // add 8% margin since fc is not very accurate
	if (BW< 6000)   BW =  6000;     // Sharp2410 LPF can be tuned form 10M to 30M, step is 2.0M
	if (BW>34000)   BW = 34000;     // the range can be 6M~~34M actually, 4M is not good

	if (BW<=10000)  LFP = 3;
	else if (BW<=12000)  LFP = 4;
	else if (BW<=14000)  LFP = 5;
	else if (BW<=16000)  LFP = 6;
	else if (BW<=18000)  LFP = 7;
	else if (BW<=20000)  LFP = 8;
	else if (BW<=22000)  LFP = 9;
	else if (BW<=24000)  LFP = 10;
	else if (BW<=26000)  LFP = 11;
	else if (BW<=28000)  LFP = 12;
	else                 LFP = 13;

	/* local oscillator select */
	DIV = 0;
    if(freq <= 1065)
	{
		BA = 6;
		DIV = 1;
	}
    else if(freq <= 1170)
	{
		BA = 7;
		DIV = 1;
	}
    else if(freq <= 1300)
		BA = 1;
	else if(freq <= 1445)
		BA = 2;
	else if(freq <= 1607)
		BA = 3;
	else if(freq <= 1778)
		BA = 4;
	else if(freq <= 1942)
		BA = 5;   
	else //if(freq <= 2150)
		BA = 6;

	//PRINTF("freq = %d,bs = %d\n",freq,sym);
	//PRINTF("BA:%d,LFP:%d,DIV:%d\n",BA,LFP,DIV);

	tmp = freq*1000 * 8 / tuner_dev_ptr->wTuner_Crystal;
	Nswa = tmp % 32;
	Npro = tmp / 32;
	//PRINTF("Npro = %d,Nswa = %d\n",Npro,Nswa);

	data[0] = (UINT8) ((Npro>>3)&0x7F);
	data[1] = Nswa | (((UINT8)Npro&0x07) << 5);
	data[2] = 0xE1;
	data[3] = (BA<<5) | (DIV<<1);
	i2c_write(tuner_dev_ptr->i2c_type_id, tuner_dev_ptr->cTuner_Base_Addr, data+0, 4);
	data[2] = 0xE5;
	i2c_write(tuner_dev_ptr->i2c_type_id, tuner_dev_ptr->cTuner_Base_Addr, data+2, 1);
	osal_delay(10000);

	data[2] |= ((LFP&0x01)<<4) | ((LFP&0x02)<<2);
	data[3] |= ((LFP&0x04)<<1) | ((LFP&0x08)>>1);

	i2c_write(tuner_dev_ptr->i2c_type_id, tuner_dev_ptr->cTuner_Base_Addr, data+2, 2);
	//PRINTF("%Tuner: %x,%x,%x,%x\n",data[0],data[1],data[2],data[3]);
	return SUCCESS;
}

/*****************************************************************************
* INT32 nim_ix2410_status(UINT8 *lock)
*
* Tuner read operation
*
* Arguments:
*  Parameter1: UINT8 *lock		: Phase lock status
*
* Return Value: INT32			: Result
*****************************************************************************/
INT32 nim_ix2410_status(UINT32 tuner_id, UINT8 *lock)
{
	INT32 result;
	UINT8 data;
	struct QPSK_TUNER_CONFIG_EXT * tuner_dev_ptr = NULL;
	if(tuner_id>=stIX2410_tuner_cnt||tuner_id>=MAX_TUNER_SUPPORT_NUM)
	{
		*lock = 0;
		return ERR_FAILUE;
	}
	tuner_dev_ptr = stIX2410_dev_id[tuner_id];
	result = i2c_read(tuner_dev_ptr->i2c_type_id, tuner_dev_ptr->cTuner_Base_Addr, &data, 1);
	*lock = ((data & 0x40) >> 6);
	PRINTF("lock = %d,result = %d\n",*lock,result);
	return result;
}

